package yueyong.salarymanagement.module.system.login;

import org.apache.commons.lang3.tuple.Pair;
import yueyong.salarymanagement.common.constant.JudgeEnum;
import yueyong.salarymanagement.common.domain.ResponseDTO;
import yueyong.salarymanagement.common.idgenerator.IdWorker;
import yueyong.salarymanagement.constant.CommonConst;
import yueyong.salarymanagement.module.business.salary.dao.VerifyCodeDao;
import yueyong.salarymanagement.module.business.salary.domain.entity.VerifyCodeEntity;
import yueyong.salarymanagement.module.system.department.DepartmentDao;
import yueyong.salarymanagement.module.system.department.domain.entity.DepartmentEntity;
import yueyong.salarymanagement.module.system.employee.EmployeeDao;
import yueyong.salarymanagement.module.system.employee.constant.EmployeeResponseCodeConst;
import yueyong.salarymanagement.module.system.employee.constant.EmployeeStatusEnum;
import yueyong.salarymanagement.module.system.employee.domain.dto.EmployeeDTO;
import yueyong.salarymanagement.module.system.employee.domain.dto.EmployeeLoginFormDTO;
import yueyong.salarymanagement.module.business.log.LogService;
import yueyong.salarymanagement.module.business.log.userloginlog.domain.UserLoginLogEntity;
import yueyong.salarymanagement.module.system.employee.domain.dto.EmployeeSubmitFormDTO;
import yueyong.salarymanagement.module.system.employee.domain.entity.EmployeeEntity;
import yueyong.salarymanagement.module.system.login.domain.KaptchaVO;
import yueyong.salarymanagement.module.system.login.domain.LoginDetailVO;
import yueyong.salarymanagement.module.system.login.domain.LoginPrivilegeDTO;
import yueyong.salarymanagement.module.system.login.domain.RequestTokenBO;
import yueyong.salarymanagement.module.system.privilege.domain.entity.PrivilegeEntity;
import yueyong.salarymanagement.module.system.privilege.service.PrivilegeEmployeeService;
import yueyong.salarymanagement.util.SendShortMessageUtil;
import yueyong.salarymanagement.util.SmartBeanUtil;
import yueyong.salarymanagement.util.SmartDigestUtil;
import yueyong.salarymanagement.util.SmartIPUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * [  ]
 *
 * @author yandanyang
 * @version 1.0
 * @company 1024lab.net
 * @copyright (c) 2018 1024lab.netInc. All rights reserved.
 * @date 2019/3/27 0027 下午 18:10
 * @since JDK1.8
 */
@Slf4j
@Service
public class LoginService {

    private static final String VERIFICATION_CODE_REDIS_PREFIX = "vc_%s";

    @Autowired
    private EmployeeDao employeeDao;

    @Autowired
    private DepartmentDao departmentDao;

    @Autowired
    private PrivilegeEmployeeService privilegeEmployeeService;

    @Autowired
    private LoginTokenService loginTokenService;

    @Autowired
    private LogService logService;

    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @Autowired
    private ValueOperations<String, String> redisValueOperations;

    @Autowired
    private VerifyCodeDao verifyCodeDao;

    public ResponseDTO<LoginDetailVO> submit(@Valid EmployeeSubmitFormDTO submitFormDTO, HttpServletRequest request) {

        //手机验证码校验
        boolean verifyCodeResult = verifyCode(submitFormDTO.getMobilePhone(), submitFormDTO.getCode());
        if(!verifyCodeResult) {
            return ResponseDTO.wrap(EmployeeResponseCodeConst.VERIFICATION_CODE_INVALID);
        }

        //判断用户是否已注册
        String loginPwd = SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, submitFormDTO.getLoginPwd());
        EmployeeDTO employeeDTO = employeeDao.login(submitFormDTO.getLoginName(), loginPwd);
        if (null != employeeDTO) {
            return ResponseDTO.wrap(EmployeeResponseCodeConst.USER_ALREADY_EXIT);
        }


        EmployeeEntity employeeEntity = new EmployeeEntity();
        employeeEntity.setLoginPwd(loginPwd);
        employeeEntity.setLoginName(submitFormDTO.getLoginName());
        employeeEntity.setActualName("x");
        employeeEntity.setDepartmentId(1L);
        employeeEntity.setCreateUser(1L);

        int result = employeeDao.insert(employeeEntity);
        if(result <1) {
            return ResponseDTO.wrap(EmployeeResponseCodeConst.CAN_NOT_SUBMIT);
        }


        EmployeeLoginFormDTO loginFormDTO = new EmployeeLoginFormDTO();
        loginFormDTO.setCode(submitFormDTO.getCode());
        loginFormDTO.setMobilePhone(submitFormDTO.getMobilePhone());
        loginFormDTO.setLoginName(submitFormDTO.getLoginName());
        loginFormDTO.setLoginPwd(submitFormDTO.getLoginPwd());

        return login(loginFormDTO, request);
    }


    /**
     * 登陆
     *
     * @param loginForm 登录名 密码
     * @return 登录用户基本信息
     */
    public ResponseDTO<LoginDetailVO> login(@Valid EmployeeLoginFormDTO loginForm, HttpServletRequest request) {
//        String redisVerificationCode = redisValueOperations.get(loginForm.getCodeUuid());
//        //增加删除已使用的验证码方式 频繁登录
//        redisValueOperations.getOperations().delete(loginForm.getCodeUuid());
//        if (StringUtils.isEmpty(redisVerificationCode)) {
//            return ResponseDTO.wrap(EmployeeResponseCodeConst.VERIFICATION_CODE_INVALID);
//        }
//        if (!redisVerificationCode.equalsIgnoreCase(loginForm.getCode())) {
//            return ResponseDTO.wrap(EmployeeResponseCodeConst.VERIFICATION_CODE_INVALID);
//        }

        //手机验证码校验
        boolean verifyCodeResult = verifyCode(loginForm.getMobilePhone(), loginForm.getCode());
        if(!verifyCodeResult) {
            return ResponseDTO.wrap(EmployeeResponseCodeConst.VERIFICATION_CODE_INVALID);
        }


        String loginPwd = SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, loginForm.getLoginPwd());
        EmployeeDTO employeeDTO = employeeDao.login(loginForm.getLoginName(), loginPwd);
        if (null == employeeDTO) {
            return ResponseDTO.wrap(EmployeeResponseCodeConst.LOGIN_FAILED);
        }
        if (EmployeeStatusEnum.DISABLED.equalsValue(employeeDTO.getIsDisabled())) {
            return ResponseDTO.wrap(EmployeeResponseCodeConst.IS_DISABLED);
        }
        //jwt token赋值
        String compactJws = loginTokenService.generateToken(employeeDTO);

        LoginDetailVO loginDTO = SmartBeanUtil.copy(employeeDTO, LoginDetailVO.class);

        //获取前端功能权限
        loginDTO.setPrivilegeList(initEmployeePrivilege(employeeDTO.getId()));

        loginDTO.setXAccessToken(compactJws);
        DepartmentEntity departmentEntity = departmentDao.selectById(employeeDTO.getDepartmentId());
        loginDTO.setDepartmentName(departmentEntity.getName());

        //判断是否为超管
        Boolean isSuperman = privilegeEmployeeService.isSuperman(loginDTO.getId());
        loginDTO.setIsSuperMan(isSuperman);
        //登陆操作日志
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        UserLoginLogEntity logEntity =
                UserLoginLogEntity.builder()
                        .userId(employeeDTO.getId())
                        .userName(employeeDTO.getActualName())
                        .remoteIp(SmartIPUtil.getRemoteIp(request))
                        .remotePort(request.getRemotePort())
                        .remoteBrowser(userAgent.getBrowser().getName())
                        .remoteOs(userAgent.getOperatingSystem().getName())
                        .loginStatus(JudgeEnum.YES.getValue()).build();
        logService.addLog(logEntity);
        return ResponseDTO.succData(loginDTO);
    }

    /**
     * 手机端退出登陆，清除token缓存
     *
     * @param requestToken
     * @return 退出登陆是否成功，bool
     */
    public ResponseDTO<Boolean> logoutByToken(RequestTokenBO requestToken) {
        privilegeEmployeeService.removeCache(requestToken.getRequestUserId());
        return ResponseDTO.succ();
    }

    /**
     * 获取验证码
     *
     * @return
     */
    public ResponseDTO<KaptchaVO> verificationCode() {
        KaptchaVO kaptchaVO = new KaptchaVO();
        String uuid = UUID.randomUUID().toString();
        String kaptchaText = defaultKaptcha.createText();

        String base64Code = "";

        BufferedImage image = defaultKaptcha.createImage(kaptchaText);
        ByteArrayOutputStream outputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", outputStream);
            base64Code = Base64.encodeBase64String(outputStream.toByteArray());
        } catch (Exception e) {
            log.error("verificationCode exception .{}", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    log.error("verificationCode outputStream close exception .{}", e);
                }
            }
        }
        kaptchaVO.setUuid(uuid);
        kaptchaVO.setCode("data:image/png;base64," + base64Code);
        redisValueOperations.set(uuid, kaptchaText, 60L, TimeUnit.SECONDS);
        return ResponseDTO.succData(kaptchaVO);
    }

    private String buildVerificationCodeRedisKey(String uuid) {
        return String.format(VERIFICATION_CODE_REDIS_PREFIX, uuid);
    }

    public boolean sendVerifyCode(long mobilePhone) {

        //生成 验证码
        IdWorker idWorker = new IdWorker(0, 0);
        long verifyCode = idWorker.nextId() % 10000;
        if(verifyCode < 1000) {
            verifyCode +=1000;
        }


        String content = SendShortMessageUtil.buildVerifyMessage(verifyCode);
        Pair<Boolean, String> result =  SendShortMessageUtil.sendShortMessage(content, String.valueOf(mobilePhone));
        if(result.getKey()) {
            return insertOrUpdateVerifyCode(mobilePhone, verifyCode);
        }
        return false;
    }

    private boolean insertOrUpdateVerifyCode(long mobilePhone, long verifyCode) {
        //更新
        List<VerifyCodeEntity> entityList = verifyCodeDao.getVerifyCodeEntityByMobilePhone(mobilePhone);
        if(entityList != null && entityList.size() >0 && entityList.get(0).getVerifyCode() != verifyCode) {
            VerifyCodeEntity entity = entityList.get(0);
            entity.setVerifyCode(verifyCode);

            Date date = Date.from(Instant.now());
            Date dateTrans = new Date(date.getTime() + 28800000L);
            entity.setUpdateTime(dateTrans);
            int updateResult = verifyCodeDao.updateById(entity);
            if(updateResult >0) {
                return true;
            }
            return true;
        }

        //插入
        VerifyCodeEntity entity = new VerifyCodeEntity();
        entity.setMobilePhone(mobilePhone);
        entity.setVerifyCode(verifyCode);
        int insertResult = verifyCodeDao.insert(entity);
        if(insertResult >0) {
            return true;
        }

        return false;
    }

    public boolean verifyCode(long mobilePhone, long verifyCode) {

        LocalDateTime dateTime = LocalDateTime.now().plusHours(8).minusMinutes(5);
        String startTime = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("verifyCode startTime" + startTime);

        List<VerifyCodeEntity> entityList = verifyCodeDao.getVerifyCodeEntityByMobilePhoneLat5Min(mobilePhone, startTime);

        if(entityList != null && entityList.size() >0 && entityList.get(0).getVerifyCode() == verifyCode) {
            return true;
        }
        return false;
    }



    /**
     * 初始化员工权限
     *
     * @param employeeId
     * @return
     */
    public List<LoginPrivilegeDTO> initEmployeePrivilege(Long employeeId) {
        List<PrivilegeEntity> privilegeList = privilegeEmployeeService.getPrivilegesByEmployeeId(employeeId);
        privilegeEmployeeService.updateCachePrivilege(employeeId, privilegeList);
        return SmartBeanUtil.copyList(privilegeList, LoginPrivilegeDTO.class);
    }

    public LoginDetailVO getSession(RequestTokenBO requestUser) {
        LoginDetailVO loginDTO = SmartBeanUtil.copy(requestUser.getEmployeeBO(), LoginDetailVO.class);
        List<PrivilegeEntity> privilegeEntityList = privilegeEmployeeService.getEmployeeAllPrivilege(requestUser.getRequestUserId());
        //======  开启缓存   ======
        if (privilegeEntityList == null) {
            List<LoginPrivilegeDTO> loginPrivilegeDTOS = initEmployeePrivilege(requestUser.getRequestUserId());
            loginDTO.setPrivilegeList(loginPrivilegeDTOS);
        } else {
            loginDTO.setPrivilegeList(SmartBeanUtil.copyList(privilegeEntityList, LoginPrivilegeDTO.class));
        }

        //======  不开启缓存   ======
//        List<LoginPrivilegeDTO> loginPrivilegeDTOS = initEmployeePrivilege(requestUser.getRequestUserId());
//        loginDTO.setPrivilegeList(loginPrivilegeDTOS);

        //判断是否为超管
        Boolean isSuperman = privilegeEmployeeService.isSuperman(loginDTO.getId());
        loginDTO.setIsSuperMan(isSuperman);
        return loginDTO;
    }
}
